package ms.jasim.console.gui;

import java.awt.BorderLayout;
import java.io.FileWriter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Timer;
import java.util.TimerTask;

import javax.swing.SwingUtilities;

import ms.jacrim.framework.Configuration;
import ms.jacrim.framework.Event;
import ms.jacrim.framework.ActiveSolution.ActionInfo;
import ms.jacrim.pddl.PddlSolution.Action;
import ms.jacrim.pddl.PddlSolution.Functor;
import ms.jasim.console.JasimClientListener;
import ms.spm.IAppContext;
import ms.utils.ExceptionUtil;
import chrriis.dj.nativeswing.swtimpl.components.JWebBrowser;
import chrriis.dj.nativeswing.swtimpl.components.WebBrowserAdapter;
import chrriis.dj.nativeswing.swtimpl.components.WebBrowserEvent;

import com.vlsolutions.swing.docking.DockKey;
import com.vlsolutions.swing.docking.DockingConstants;

public class AgentTimelineDockPane extends DefaultDockPane {

	private static final long serialVersionUID = 1L;

	private String eventOutput = "timeline/src/webapp/data/events.xml";
	private SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd yyyy HH:mm:ss 'GMT'Z");
	private Timer refreshTimer;
	private JWebBrowser wb;

	/**
	 * Create the panel
	 */
	public AgentTimelineDockPane(IAppContext context) {
		super(context);
		//
		wb = new JWebBrowser(JWebBrowser.destroyOnFinalization());
		wb.setMenuBarVisible(false);
		wb.setBarsVisible(false);
		wb.setStatusBarVisible(false);
		add(wb, BorderLayout.CENTER);

		wb.navigate("http://localhost/timeline/webapp/index.html");
		wb.addWebBrowserListener(new WebBrowserAdapter() {
			@Override
			public void commandReceived(WebBrowserEvent e, String command, String[] args) {
				try {
					svcJasim.sendCommand(command);
				} catch (IOException e1) {
				}
			}
		});

		refreshTimer = new Timer();
		refreshTimer.schedule(new TimerTask() {

			@Override
			public void run() {
				refresh();
			}

		}, 0, 1000 * 60);

		refresh();
	}

	@Override
	protected DockKey createDocKey() {
		DockKey key = new DockKey(this.getClass().getName(), "Agent Timeline", "", null, DockingConstants.HIDE_BOTTOM);
		key.setAutoHideEnabled(false);
		key.setCloseEnabled(false);
		return key;
	}

	@Override
	protected void setupContext() {
		super.setupContext();

		Configuration cfg = context.getService(Configuration.class);
		eventOutput = cfg.get("event_output", eventOutput);

		svcJasim.addListener(new JasimClientListener() {
			@Override
			public void notifyListener() {
				refresh();
			}
		});
	}

	private String generateEventData() {
		StringBuilder result = new StringBuilder();
		result.append("<data>\n");

		ArrayList<Event> events = (ArrayList<Event>) svcJasim.getEvents();
		if (events != null) {
			// sort the actions list according to action's actor
			Collections.sort(events, new Comparator<Event>() {
				@Override
				public int compare(Event o1, Event o2) {
					long result = o1.getStart().getTime() - o2.getStart().getTime();
					if (result == 0)
						result = o1.getTitle().compareTo(o2.getTitle());
					return (int) result;
				}
			});

			for (Event event : events) {
				if (event.getActionInfo() == null || event.getActionInfo().Action.getFunctor() == Functor.SATISFIES)
					addEvent(result, event);
			}
		}

		result.append("</data>\n");
		return result.toString();
	}

	private void addEvent(StringBuilder result, Event event) {
		String template = "<event start=\"%s\" end=\"%s\" title=\"%s\" caption=\"%s\" color=\"%s\" icon=\"%s\">%s</event>\n";
		String title = event.getTitle();
		String caption = String.format("%s\nStart: %s\nEnd: %s", title, sdf.format(event.getStart()), sdf
				.format(event.getResolvedEnd(true)));
		String icon = event.isFinished() ? "" : "../images/dark-red-circle.png";
		String description = event.getDescription();
		if (description == null)
			description = "";
		String color = event.isFinished() ? "green" : "red";
		if (event.getActionInfo() != null) {
			ActionInfo info = event.getActionInfo();
			description = getActionDescription(info.Action);
			// JasimAgent ag = svcJasim.getAgent(info.Action.Argument(0));
			if (info.Action.getFunctor() == Functor.SATISFIES && !event.isFinished()) {
				description += String.format("&lt;p&gt; Click to &lt;a href=\"command://fulfill %s\"&gt;fulfill&lt;/a&gt;", info.Action
						.Argument(1));
			}
		}
		result.append(String.format(template, sdf.format(event.getStart()), sdf.format(event.getResolvedEnd(true)), title, caption, color,
				icon, description));

	}

	private String getActionDescription(Action act) {
		String result = null;
		if ("PASSES".equalsIgnoreCase(act.Name()))
			result = String.format("%s delegates goal %s to %s", act.Argument(0), act.Argument(2), act.Argument(1));
		// else if ("SATISFIES".equalsIgnoreCase(act.Name()))
		// result = String.format("%s fulfills goal %s", act.Argument(0),
		// act.Argument(1));
		else if ("SATISFIES".equalsIgnoreCase(act.Name()))
			result = String.format("%s satisfies goal %s", act.Argument(0), act
					.Argument(1));
		else if ("AND_DECOMPOSES2".equalsIgnoreCase(act.Name()))
			result = String.format("%s descomposes goal %s to %s and %s", act.Argument(0), act.Argument(1), act.Argument(2), act
					.Argument(2));
		else if ("AND_DECOMPOSES3".equalsIgnoreCase(act.Name()))
			result = String.format("%s descomposes goal %s to %s, %s and %s", act.Argument(0), act.Argument(1), act.Argument(2), act
					.Argument(2), act.Argument(3));
		return result;
	}

	@SuppressWarnings("unused")
	private String getActionTitle(Action act) {
		String result = null;
		if ("PASSES".equalsIgnoreCase(act.Name()))
			result = String.format("%s passes %s to %s", act.Argument(0), act.Argument(2), act.Argument(1));
		else if ("SATISFIES".equalsIgnoreCase(act.Name()))
			result = String.format("%s satisfies %s", act.Argument(0), act
					.Argument(1));
		else if ("AND_DECOMPOSES2".equalsIgnoreCase(act.Name()))
			result = String.format("%s descomposes %s", act.Argument(0), act.Argument(1), act.Argument(2), act.Argument(2));
		else if ("AND_DECOMPOSES3".equalsIgnoreCase(act.Name()))
			result = String
					.format("%s descomposes %s", act.Argument(0), act.Argument(1), act.Argument(2), act.Argument(2), act.Argument(3));
		return result;
	}

	private void refresh() {
		try {
			System.out.println("refreshing timeline...");
			FileWriter fw = new FileWriter(eventOutput, false);
			fw.write(generateEventData());
			fw.close();
		} catch (IOException e1) {
			ExceptionUtil.handle(e1, context);
		}
		SwingUtilities.invokeLater(new Runnable() {
			@Override
			public void run() {
				try {
					if (wb != null)
						wb.executeJavascript("reloadData();");
				} catch (Exception e) {
					ExceptionUtil.handle(e, context);
				}
			}
		});
		
	}
}
